package com.ibeeking.gmc.global.g.rest.service.impl;

import com.ibeeking.gmc.global.g.rest.service.IClientService;
import com.ibeeking.found.common.base.BaseDO;
import com.ibeeking.found.common.enums.PublishStatusEnum;
import com.ibeeking.found.common.utils.UserUtils;
import com.ibeeking.gmc.global.service.common.bo.OauthClientBO;
import com.ibeeking.gmc.global.service.common.dos.OauthClientDO;
import com.ibeeking.gmc.global.service.common.param.OauthClientParam;
import com.ibeeking.gmc.global.service.common.query.ClientPageQuery;
import com.ibeeking.gmc.global.service.common.vo.OauthClientPageVO;
import com.ibeeking.gmc.global.service.common.vo.OauthClientVO;
import com.ibeeking.gmc.global.service.mapper.ClientsMapper;
import com.ibeeking.nematos.core.utils.SpringBeanUtil;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.redis.utils.RedisUtils;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.StringUtils;
import com.ibeeking.nematos.utils.id.IdGen;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * @ClassName ClientServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2020-11-17 21:39
 **/
@Service
public class ClientServiceImpl implements IClientService {

    private static final String CLIENT_KEY = "CLIENT_KEY";

    @Resource
    private ClientsMapper clientsMapper;
    @Resource
    private BCryptPasswordEncoder passwordEncoder;
    @Resource
    private RedisUtils redisUtils;

    @Override
    public OauthClientBO queryByClientId(String clientId) {
        if (StringUtils.isEmpty(clientId)) {
            return null;
        }
        Object o = redisUtils.hGet(CLIENT_KEY, clientId);
        if (o != null) {
            return (OauthClientBO) o;
        } else {
            LambdaQueryWrapper<OauthClientDO> queryWrapper = new LambdaQueryWrapper<>(OauthClientDO.class)
                    .eq(OauthClientDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue())
                    .eq(OauthClientDO::getClientId, clientId);
            OauthClientDO oauthClientDO = clientsMapper.selectOne(queryWrapper);
            if (null != oauthClientDO) {
                OauthClientBO oauthClientBO = BeanUtil.convertBean(oauthClientDO, OauthClientBO.class);
                redisUtils.hSet(CLIENT_KEY, clientId, oauthClientBO);
                return oauthClientBO;
            }
            return null;
        }
    }

    @Override
    public Page<OauthClientPageVO> pageList(ClientPageQuery query) {
        LambdaQueryWrapper<OauthClientDO> queryWrapper = new LambdaQueryWrapper<>(OauthClientDO.class)
                .orderByDesc(BaseDO::getCreateTime)
                .likeRight(StringUtils.isNotBlank(query.getClientId()), OauthClientDO::getClientId, query.getClientId());
        Page<OauthClientDO> page = clientsMapper.selectPage(new Page<>(query.getPageNum(), query.getPageSize()), queryWrapper);
        return BeanUtil.convertPage(page, OauthClientPageVO.class);
    }

    @Override
    public OauthClientVO add(OauthClientParam param) {
        OauthClientDO oauthClientDO = BeanUtil.convertBean(param, OauthClientDO.class);
        if (!checkUnique(oauthClientDO)) {
            throw new BusinessException("当前clientId已存在");
        }
        String clientSecret = IdGen.randomStr(18);
        oauthClientDO.setClientSecret(passwordEncoder.encode(clientSecret));
        if (StringUtils.isBlank(param.getScope())) {
            oauthClientDO.setScope("all");
        }
        if (null == param.getAccessTokenValidity()) {
            oauthClientDO.setAccessTokenValidity(7200);
        }
        if (null == param.getRefreshTokenValidity()) {
            oauthClientDO.setRefreshTokenValidity(2592000);
        }
        if (null == param.getAutoApprove() || 1 == param.getAutoApprove()) {
            oauthClientDO.setAutoApprove("true");
        } else if (0 == param.getAutoApprove()) {
            oauthClientDO.setAutoApprove("false");
        }
        oauthClientDO.setCreateBy(UserUtils.getUserId());
        oauthClientDO.setCreateTime(LocalDateTime.now());
        oauthClientDO.setModifyTime(LocalDateTime.now());
        clientsMapper.insert(oauthClientDO);
        OauthClientVO result = new OauthClientVO();
        result.setClientId(oauthClientDO.getClientId());
        result.setClientSecret(clientSecret);
        return result;
    }

    @Override
    public Boolean modify(OauthClientParam param) {
        OauthClientDO oauthClientDO = BeanUtil.convertBean(param, OauthClientDO.class);
        oauthClientDO.setClientId(null);
        if (StringUtils.isBlank(param.getScope())) {
            oauthClientDO.setScope("all");
        }
        if (null == param.getAccessTokenValidity()) {
            oauthClientDO.setAccessTokenValidity(7200);
        }
        if (null == param.getRefreshTokenValidity()) {
            oauthClientDO.setRefreshTokenValidity(2592000);
        }
        if (null == param.getAutoApprove() || 1 == param.getAutoApprove()) {
            oauthClientDO.setAutoApprove("true");
        } else if (0 == param.getAutoApprove()) {
            oauthClientDO.setAutoApprove("false");
        }
        oauthClientDO.setModifyBy(UserUtils.getUserId());
        oauthClientDO.setModifyTime(LocalDateTime.now());
        return clientsMapper.updateById(oauthClientDO) > 0;
    }

    @Override
    public OauthClientVO view(Long id) {
        OauthClientBO oauthClientBO = getBean().queryById(id);
        return BeanUtil.convertBean(oauthClientBO, OauthClientVO.class);
    }

    @Override
    public OauthClientBO queryById(Long id) {
        OauthClientDO oauthClientDO = clientsMapper.selectById(id);
        return BeanUtil.convertBean(oauthClientDO, OauthClientBO.class);
    }

    @Override
    public Boolean changeStatus(Long id, Integer status) {
        OauthClientDO oauthClientDO = new OauthClientDO();
        oauthClientDO.setId(id);
        oauthClientDO.setPublishStatus(status);
        oauthClientDO.setModifyBy(UserUtils.getUserId());
        oauthClientDO.setModifyTime(LocalDateTime.now());
        return clientsMapper.updateById(oauthClientDO) > 0;
    }

    @Override
    public Boolean del(Long id) {
        OauthClientBO oauthClientBO = getBean().queryById(id);
        if (PublishStatusEnum.ENABLE.getValue().equals(oauthClientBO.getPublishStatus())) {
            throw new BusinessException("请先禁用后再删除");
        }
        return clientsMapper.deleteById(id) > 0;
    }

    @Override
    public OauthClientVO reset(Long id) {
        OauthClientDO oauthClientDO = new OauthClientDO();
        oauthClientDO.setId(id);
        String clientSecret = IdGen.randomStr(18);
        oauthClientDO.setClientSecret(passwordEncoder.encode(clientSecret));
        clientsMapper.updateById(oauthClientDO);
        OauthClientVO result =new OauthClientVO();
        result.setClientSecret(clientSecret);
        return result;
    }

    private Boolean checkUnique(OauthClientDO clientDO) {
        Integer count = clientsMapper.selectCount(new LambdaQueryWrapper<>(OauthClientDO.class)
                .ne(null != clientDO.getId(), OauthClientDO::getId, clientDO.getId())
                .and(
                        Wrapper -> Wrapper
                                /*.eq(StringUtils.isNotBlank(roleDO.getCode()), CsRoleDO::getCode, roleDO.getCode())
                                .or()*/
                                .eq(StringUtils.isNotBlank(clientDO.getClientId()), OauthClientDO::getClientId, clientDO.getClientId())
                )
        );
        return 0 == count;
    }

    private static IClientService getBean() {
        return SpringBeanUtil.getBean(IClientService.class);
    }
}
